/************************************************************
 * Project Name         [Thinking_In_Java]
 * File Name            [SketchpadPanel.java]
 * Creation Date        [12-Jul-2014]
 * 
 * Copyright© ge.y.yang@gmail.com All Rights Reserved
 * 
 * Work hard, play harder, think big and keep fit
 ************************************************************/
package pkg_02_gui.sketchpad.ui;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Enumeration;
import java.util.Stack;

import pkg_02_gui.sketchpad.command.ShapeCommand;
import pkg_02_gui.sketchpad.shape.Circle;
import pkg_02_gui.sketchpad.shape.Line;
import pkg_02_gui.sketchpad.shape.Rectangle;
import pkg_02_gui.sketchpad.shape.Shape;

/**
 * 
 * @author 不落的太阳(Sean Yang)
 * @version 1.0
 * @since JDK 6
 * 
 */
public class SketchpadPanel extends Canvas implements MouseListener,
		MouseMotionListener {

	private static final long serialVersionUID = -5229161042153132522L;

	// 鼠标点击起始坐标和当前坐标
	private int beginX = 0, beginY = 0, currentX = 0, currentY = 0;

	// 判断鼠标是否被按下
	private boolean isMousePressing = false;

	// 保存当前的图形, 在撤销和恢复时使用
	private final Stack<Shape> currentShapes = new Stack<Shape>();

	// 保存已经删除过的图形
	private final Stack<Shape> deletedShapes = new Stack<Shape>();

	private ShapeCommand command;
	private Color color;

	public SketchpadPanel() {
		addMouseListener(this);
		addMouseMotionListener(this);
	}

	/**
	 * 撤销方法
	 */
	public void undo() {
		if (currentShapes.size() > 0) {
			// 从所有保存过的图形中取出最后一个, 放入到已删除的图形中去
			Shape shape = currentShapes.pop();
			deletedShapes.push(shape);
			repaint();
		}
	}

	/**
	 * 恢复撤销方法
	 */
	public void redo() {
		if (deletedShapes.size() > 0) {
			// 从所有删除的图形中取出最后一个, 放入保存的图形中
			Shape shape = deletedShapes.pop();
			currentShapes.push(shape);
			repaint();
		}
	}

	/**
	 * 设置命令
	 * 
	 * @param command
	 */
	public void setCommand(ShapeCommand command) {
		this.command = command;
	}

	/**
	 * 设置颜色
	 * 
	 * @param color
	 */
	public void setColor(Color color) {
		this.color = color;
	}

	/**
	 * 在java中repaint()是通过两个步骤来实现刷新功能的<br>
	 * 首先它调用public void update()来刷新屏幕<br>
	 * 其次再调用paint(Graphcis g)来重画屏幕<br>
	 * 
	 * 这就容易造成闪烁, 特别是一些需要重画背景的程序, 如果下一桢图象可以完全覆盖上一桢图象的话, 可以重写update如下函数来消除闪烁:<br>
	 * public void update(Graphics g){ paint(g)} 同样调用repaint()重画屏幕<br>
	 * 
	 * 或者直接重写而不调用repaint, 而用Graphics g=getGraphics(); paint(g);来实现重画屏幕
	 */
	public void updete(Graphics g) {
		paint(g);
	}

	/**
	 * 绘制画板
	 */
	@Override
	public void paint(Graphics g) {
		// 绘制画板
		Dimension size = getSize();
		int width = size.width;
		int height = size.height;
		g.setColor(Color.WHITE);
		g.fillRect(0, 0, width, height);

		// 绘制所有图形
		Shape shape = null;
		Enumeration<Shape> e = currentShapes.elements();
		while (e.hasMoreElements()) {
			shape = e.nextElement();
			shape.paint(g);
		}

		// 如果当前鼠标没有释放
		if (isMousePressing) {
			g.setColor(color);
			switch (command) {
			// 绘制直线
			case LINE:
				g.drawLine(beginX, beginY, currentX, currentY);
				break;
			// 绘制矩形
			case RECTANGLE:
				if (currentX < beginX) {
					if (currentY < beginY) {
						// 如果当前位置在起始位置的左上方, 则以鼠标当前位置为矩形的左上角位置
						g.drawRect(currentX, currentY, beginX - currentX,
								beginY - currentY);
					} else {
						// 如果当前位置在起始位置的左下方, 则以鼠标当前位置的横坐标和起始位置的纵坐标作为矩形的左上角位置
						g.drawRect(currentX, beginY, beginX - currentX,
								currentY - beginY);
					}
				} else {
					if (currentY < beginY) {
						// 如果当前位置在起始位置的右上方, 则以鼠标起始位置的很坐标和当前位置的纵坐标作为矩形的左上角位置
						g.drawRect(beginX, currentY, currentX - beginX, beginY
								- currentY);
					} else {
						// 如果当前位置在起始位置的右下方, 则已起始位置作为矩形的左上叫位置
						g.drawRect(beginX, beginY, currentX - beginX, currentY
								- beginY);
					}
				}
				break;
			// 绘制圆形
			case CIRCLE:
				// 半径为a*a + b*b的平方根
				int radius = (int) Math.sqrt((beginX - currentX)
						* (beginX - currentX) + (beginY - currentY)
						* (beginY - currentY));
				g.drawArc(beginX - radius / 2, beginY - radius / 2, radius,
						radius, 0, 360);
				break;
			}
		}

	}

	@Override
	public void mouseClicked(MouseEvent e) {

	}

	@Override
	public void mouseEntered(MouseEvent e) {

	}

	@Override
	public void mouseExited(MouseEvent e) {

	}

	/**
	 * 当鼠标按下的时候获得起始坐标
	 */
	@Override
	public void mousePressed(MouseEvent e) {
		beginX = e.getX();
		beginY = e.getY();
		isMousePressing = true;
	}

	/**
	 * 当鼠标释放时获得当前坐标
	 */
	@Override
	public void mouseReleased(MouseEvent e) {
		currentX = e.getX();
		currentY = e.getY();
		isMousePressing = false;

		// 当释放鼠标时, 将绘制的图形保存到shapes中
		switch (command) {
		// 绘制直线
		case LINE:
			Line line = new Line(beginX, beginY, currentX, currentY, color);
			currentShapes.push(line);
			break;
		// 绘制圆形
		case CIRCLE:
			// 半径为a*a + b*b的平方根
			int radius = (int) Math.sqrt((beginX - currentX)
					* (beginX - currentX) + (beginY - currentY)
					* (beginY - currentY));
			Circle circle = new Circle(beginX - radius / 2,
					beginY - radius / 2, radius, color);
			currentShapes.push(circle);
			break;
		// 绘制矩形
		case RECTANGLE:
			Rectangle rectangle = null;
			if (currentX < beginX) {
				if (currentY < beginY) {
					rectangle = new Rectangle(currentX, currentY, beginX
							- currentX, beginY - currentY, color);
				} else {
					rectangle = new Rectangle(currentX, beginY, beginX
							- currentX, currentY - beginY, color);
				}
			} else {
				if (currentY < beginY) {
					rectangle = new Rectangle(beginX, currentY, currentX
							- beginX, beginY - currentY, color);
				} else {
					rectangle = new Rectangle(beginX, beginY,
							currentX - beginX, currentY - beginY, color);
				}
			}
			currentShapes.push(rectangle);
			break;
		}

		repaint();
	}

	@Override
	public void mouseDragged(MouseEvent e) {
		currentX = e.getX();
		currentY = e.getY();
		this.repaint();
	}

	@Override
	public void mouseMoved(MouseEvent e) {

	}
}
